<?php

class Dispatch_Core {
	protected $controller;

	/**
	 * Initalizes controller. Returns dispatch object for method chaining.
	 *
	 * @param string $controller
	 * @return Dispatch
	 */
	public static function controller($controller)
	{
		$controller_file = strtolower($controller);

		// Set controller class name
		$controller = ucfirst($controller) . '_Controller';

		if(!class_exists($controller, FALSE))
		{
			// If the file doesn't exist, just return
			if (($filepath = Kohana::find_file('controllers', $controller_file)) === FALSE)
			{
				return FALSE;
			}

			// Include the Controller file
			require_once $filepath;
		}

		// Run dispatch.pre_controller
		Event::run('dispatch.pre_controller');

		// Initialize the controller
		$controller = new $controller;

		// Run dispatch.post_controller_constructor
		Event::run('dispatch.post_controller_constructor');

		// Return Dispatch object for chaining
		return new Dispatch($controller);
	}

	/**
	 * Executes and returns output of controller method unless method
	 * returns FALSE (in which case FALSE is returned).
	 *
	 * @param string $method
	 * @param array $arguments
	 * @return boolean|string
	 */
	public function method($method, $arguments=NULL)
	{
		// Check to be sure method exists
		if(!method_exists($this->controller, $method))
		{
			return FALSE;
		}

		if (method_exists($this->controller, '_remap'))
		{
			// Make the arguments routed
			$arguments = array($method, $arguments);

			// The method becomes part of the arguments
			array_unshift($arguments, $method);

			// Set the method to _remap
			$method = '_remap';
		}

		// Start output buffering
		ob_start();

		// Arguments MUST be an array
		if(!is_array($arguments))
		{
			$arguments = array($arguments);
		}

		// Call method with arguments
		switch(count($arguments))
		{
			case 1:
				$result = $this->controller->$method($arguments[0]);
			break;
			case 2:
				$result = $this->controller->$method($arguments[0], $arguments[1]);
			break;
			case 3:
				$result = $this->controller->$method($arguments[0], $arguments[1], $arguments[2]);
			break;
			case 4:
				$result = $this->controller->$method($arguments[0], $arguments[1], $arguments[2], $arguments[3]);
			break;
			default:
				// Resort to using call_user_func_array for many segments
				$result = call_user_func_array(array($this->controller, $method), $arguments);
			break;
		}

		// Run dispatch.post_controller
		Event::run('dispatch.post_controller');

		// Get and return output
		$result = ob_get_contents();
		ob_end_clean();
		return $result;
	}

	public function __construct(Controller $controller)
	{
		$this->controller = $controller;
	}

	public function __get($key)
	{
		if($key == 'controller')
		{
			return $this->$key;
		}
		else
		{
			return $this->controller->$key;
		}
	}

	public function __set($key,$value)
	{
		$this->controller->$key = $value;
	}

	public function __call($name, $arguments=null)
	{
		return $this->method($name, $arguments);
	}
}
?>